package com.huajx.mina.tcpserver.codec;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.nio.ByteOrder;
import java.nio.charset.Charset;

import com.huajx.util.ObjectUtil;
import com.huajx.util.StrUtil;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LdDecoderAdapter extends CumulativeProtocolDecoder {
	static final byte CONTENT_CLOSING_TAG = 64;
	private static final AttributeKey KEY_DECRYPTOR = new AttributeKey(LdDecoderAdapter.class, "Decryptor");
	private static final AttributeKey KEY_SECRETKEY = new AttributeKey(LdDecoderAdapter.class, "SecretKey");
	private static final AttributeKey KEY_MEMORYSTREAM = new AttributeKey(LdDecoderAdapter.class, "MemoryStream");
	private final Charset codePage;
	private final boolean isServer;
	private final boolean isPassiveEncryption;
	
	private final Logger logger = LoggerFactory.getLogger(LdDecoderAdapter.class);

	public LdDecoderAdapter(Charset charset, boolean isServer, boolean isPassiveEncryption) {
		this.codePage = charset;
		this.isServer = isServer;
		this.isPassiveEncryption = isPassiveEncryption;
	}

	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		String secretKey = (String) session.getAttribute(KEY_SECRETKEY);
		if (this.isServer) {
			if (StrUtil.isBlank(secretKey)) {
				int size = in.remaining();
				if (size > 0) {
					byte[] Source = new byte[size];
					in.get(Source);

					ByteArrayOutputStream MemoryStream = getMemoryStream(session);
					if (Source[(Source.length - 1)] == CONTENT_CLOSING_TAG) {
						String Message;
						if (MemoryStream.size() == 0) {
							Message = new String(Source, this.codePage);
						} else {
							MemoryStream.write(Source);
							Message = new String(MemoryStream.toByteArray(), this.codePage);
							MemoryStream.reset();
						}
						if (Message.startsWith("GetLicense(")) {
//							DoLicense(session, Message);
						} else if (this.isPassiveEncryption) {
							session.closeNow();
						} else {
							out.write(Message);
						}
					} else {
						MemoryStream.write(Source);
					}
				}
			} else {
				super.decode(session, in, out);
			}
		} else {
			int size = in.remaining();
			if (size > 0) {
				byte[] Source = new byte[size];
				in.get(Source);
				if (StrUtil.isNotBlank(secretKey)) {
					// Xor64Codec Decryptor = (Xor64Codec)getDecryptor(session,
					// SecretKey);
					// Source = Decryptor.Transform(Source, 0, size);
				}
				ByteArrayOutputStream MemoryStream = getMemoryStream(session);
				if (ObjectUtil.indexOf(Source, CONTENT_CLOSING_TAG) == -1) {
					MemoryStream.write(Source);
				} else if (MemoryStream.size() == 0) {
					out.write(new String(Source, this.codePage));
				} else {
					MemoryStream.write(Source);
					out.write(new String(MemoryStream.toByteArray(), this.codePage));
					MemoryStream.reset();
				}
			}
		}
	}

	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		if (in.remaining() >= 4) {
			in.mark();
			byte[] SizeByteArray = new byte[4];
			in.get(SizeByteArray);
			int Size = ObjectUtil.toInt32(SizeByteArray, 0, ByteOrder.BIG_ENDIAN);
			logger.info("包长度:{}", Size);
			if (Size == 0) {
				return in.hasRemaining();
			}
			if (in.remaining() >= Size) {
				return in.hasRemaining();
			}
			in.reset();
		}
		return false;
	}

	public void dispose(IoSession session) throws Exception {
		Closeable Decryptor = (Closeable) session.getAttribute(KEY_DECRYPTOR);
		if (Decryptor != null) {
			Decryptor.close();
		}
		session.removeAttribute(KEY_DECRYPTOR);
		session.removeAttribute(KEY_SECRETKEY);

		ByteArrayOutputStream MemoryStream = (ByteArrayOutputStream) session.getAttribute(KEY_MEMORYSTREAM);
		if (MemoryStream != null) {
			MemoryStream.close();
		}
		session.removeAttribute(KEY_MEMORYSTREAM);
	}

	private ByteArrayOutputStream getMemoryStream(IoSession session) {
		ByteArrayOutputStream MemoryStream = (ByteArrayOutputStream) session.getAttribute(KEY_MEMORYSTREAM);
		if (MemoryStream == null) {
			MemoryStream = new ByteArrayOutputStream(2048);
			session.setAttribute(KEY_MEMORYSTREAM, MemoryStream);
		}
		return MemoryStream;
	}

	public Charset getCharset() {
		return this.codePage;
	}

	public boolean getIsServer() {
		return this.isServer;
	}

	public boolean getIsPassiveEncryption() {
		return this.isPassiveEncryption;
	}

	public static void setSecretKey(IoSession session, String key) {
		session.setAttribute(KEY_SECRETKEY, key);
	}

	public static String getSecretKey(IoSession session) {
		return (String) session.getAttribute(KEY_SECRETKEY);
	}

}
